﻿using System.Collections.Generic;
using System.Windows;
using SLPerlinNoise;
using GameEngine.View.Components;
using System.Xml.Linq;
using GameEngine.Libs;
using System;
using MapEngine;

namespace GameEngine.Model.Data
{
    /*
    vila e para as "quintas"
    cada condado tem x hexag de cada bem
    t: 20 espacos gerais
    t: 20 espacos para edificios
    100? 10*10
 * 
 * castelo
    * armazem
    * esconderijo
 * mercado
 * quartel
 * oficina
 *  máquinas de guerra
 * academia
 *    pesquisa de...
 * 
 * castelo
 *   academia
 * outpost
 *   como conquistar?
 * dos dois
 *  armazem
 *  esconderijo
 *  mercado 
 *  quartel
 *  oficina 
 * 
 */

    public class MapVO<ThingVOId> : IMapVO<ThingVOId>
        where ThingVOId : IComparable<ThingVOId>
    {

        //Properties

        public string Name { get; set; }
        public Point Size
        {
            get {
                return new Point(Tiles.Count,Tiles.Count==0?0: Tiles[0].Count);
            }
        }
        public TileType TileType { get; set; }
        public MapType MapType { get; set; }
        //public enum Type { Normal, Perlin }
        //public Type type = Type.Normal;
        public List<IViewVOId<ThingVOId>> SimpleViews { get; set; }

        //Containers

        public List<List<ITileVO>> Tiles { get; set; }
        public ICameraVO Camera { get; set; }

        public MapVO(string name)
        {
            Init();
            Name = name;
        }

        public MapVO()
        {
            Init();            
        }

        private void Init() {
            Camera = new CameraVO();
            TileType = TileType.Square;
            MapType = MapType.Isometric;
            Tiles = new List<List<ITileVO>>();
            SimpleViews = new List<IViewVOId<ThingVOId>>();
        }

        // iuse PerlinNoise3D.GenerateHeightsFromPerlin
        //public void GenerateHeightsFromPerlin(Point origin, float frequency, float amplitude, float persistence, int octaves, int seed/*,float maxHeight*/)
        //{
        //    PerlinNoise3D Generator = new PerlinNoise3D();
        //    //Map.type = MapVO.Type.Perlin;
        //    Generator.Frequency = frequency;
        //    Generator.Amplitude = amplitude;
        //    Generator.Persistence = persistence;
        //    Generator.Octaves = octaves;
        //    Generator.Seed = seed;
        //    //Map.Size.X = -1;
        //    //Map.Size.Y = -1;
        //    foreach (List<ITileVO> row in Tiles)
        //    {
        //        foreach (ITileVO tile in row)
        //        {
        //            tile.Height = Generator.Compute((float)(tile.Position.X + origin.X), (float)(tile.Position.Y + origin.Y), 0)*100;
        //        }
        //    }
        //}

        public void CreateTiles(Point size)
        {
            Tiles.Clear();
            List<List<ITileVO>> list = new List<List<ITileVO>>();
            for (int i = 0; i < size.X; i++)
            {
                List<ITileVO> miniList = new List<ITileVO>();
                for (int j = 0; j < size.Y; j++)
                {
                    ITileVO tile = ApplicationFacade.Instance.CreateTileVO();
                    tile.Height = 0;
                    tile.Position = new Point() { X = i, Y = j };
                    miniList.Add(tile);
                }
                list.Add(miniList);
            }

            Tiles = list;
            //type = MapVO.Type.Normal;
        }


        public virtual string Serialize()
        {
            //return Serializer.Serialize(VO);
            XDocument doc = new XDocument();
            XElement mainNode = new XElement("MapVO");
            mainNode.SetAttributeValue("Class", GetType());
            {
                XElement node = new XElement("Name") { Value = Name };
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("TileType")  { Value = TileType.ToString() };
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("MapType") { Value = MapType.ToString() };
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Camera", new XAttribute("Class", Camera.GetType()));
                node.Add(new XCData(Serializer.Serialize(Camera)));
                mainNode.Add(node);
            }
            {
                XElement node = new XElement("Tiles");
                foreach (var row in Tiles)
                {
                    XElement rowXml = new XElement("Row", new XAttribute("Class", row.GetType()));
                    foreach (var tile in row) {
                        XElement nodeXml = new XElement("Tile", new XAttribute("Class", tile.GetType()));
                        nodeXml.Add(tile.Serialize());
                        rowXml.Add(nodeXml);
                    }
                    node.Add(rowXml);
                }
                mainNode.Add(node);
            }
            return mainNode.ToString();
        }

        public virtual void DeSerialize(string serializedString)
        {
            XElement mainNode = XElement.Parse(serializedString);
            foreach (XElement node in mainNode.Nodes())
            {
                switch (node.Name.LocalName)
                {
                    case "Name":
                        Name = node.Value;
                        break;
                    case "Camera":
                        {
                            var className = node.Attribute("Class").Value;
                            var classType = Serializer.GetType(className);
                            Camera = (ICameraVO)Serializer.DeSerialize(classType, node.Value);
                        }
                        break;
                    case "TileType":
                        TileType = (TileType)Enum.Parse(typeof(TileType), node.Value,false);
                        break;
                    case "MapType":
                        MapType = (MapType)Enum.Parse(typeof(MapType), node.Value, false);
                        break;
                    case "Tiles":
                        {
                            foreach (var row in node.Elements())
                            {
                                var rowList = new List<ITileVO>();
                                Tiles.Add(rowList);
                                foreach (var tile in row.Elements()) {
                                    var className = tile.Attribute("Class").Value;
                                    var classType = Serializer.GetType(className);
                                    var instance = Activator.CreateInstance(classType) as ITileVO;
                                    instance.DeSerialize(tile.Value);
                                    rowList.Add(instance);
                                }
                            }
                        }
                        break;
                }
            }
        }
    }
}